﻿#include "Buffers.h"
#include "Render/VulkanContext.h"
CVulkanVertexBuffer::CVulkanVertexBuffer(uint64_t InSize)
{
    Size=InSize;

    vk::BufferCreateInfo BufferCreateInfo=vk::BufferCreateInfo()
        .setSize(Size)
        .setUsage(vk::BufferUsageFlagBits::eVertexBuffer)
        .setSharingMode(vk::SharingMode::eExclusive);
    
    AutoRecycleBuffer.Buffer=CVulkanContext::Get()->GetDevice().createBuffer(BufferCreateInfo);

    vk::MemoryRequirements MemoryRequirements=CVulkanContext::Get()->GetDevice().getBufferMemoryRequirements(AutoRecycleBuffer.Buffer);

    uint32_t MemoryTypeIndex=CVulkanContext::Get()->GetMemoryTypeIndex(MemoryRequirements, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);

    AutoRecycleBuffer.MemoryBlock=CVulkanContext::Get()->GetMemoryPools()->AllocateBlock(
        EVulkanMemoryUsage::VertexBuffer
        ,MemoryTypeIndex
        ,MemoryRequirements
        );

    CVulkanContext::Get()->GetDevice().bindBufferMemory(AutoRecycleBuffer.Buffer, AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset);
}

void CVulkanVertexBuffer::WriteData(const void *Data, uint64_t InSize)
{
    void* DataPtr = CVulkanContext::Get()->GetDevice().mapMemory(AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset, Size);
    memcpy(DataPtr, Data, InSize);
    CVulkanContext::Get()->GetDevice().unmapMemory(AutoRecycleBuffer.MemoryBlock.Memory);
}

CVulkanIndexBuffer::CVulkanIndexBuffer(uint64_t InSize)
{
    Size=InSize;

    vk::BufferCreateInfo BufferCreateInfo=vk::BufferCreateInfo()
        .setSize(Size)
        .setUsage(vk::BufferUsageFlagBits::eIndexBuffer)
        .setSharingMode(vk::SharingMode::eExclusive);

    AutoRecycleBuffer.Buffer=CVulkanContext::Get()->GetDevice().createBuffer(BufferCreateInfo);

    vk::MemoryRequirements MemoryRequirements=CVulkanContext::Get()->GetDevice().getBufferMemoryRequirements(AutoRecycleBuffer.Buffer);

    uint32_t MemoryTypeIndex=CVulkanContext::Get()->GetMemoryTypeIndex(MemoryRequirements, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);

    AutoRecycleBuffer.MemoryBlock=CVulkanContext::Get()->GetMemoryPools()->AllocateBlock(
        EVulkanMemoryUsage::IndexBuffer
        ,MemoryTypeIndex
        ,MemoryRequirements
        );

    CVulkanContext::Get()->GetDevice().bindBufferMemory(AutoRecycleBuffer.Buffer, AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset);

}


void CVulkanIndexBuffer::WriteData(const void *Data, uint64_t InSize)
{
    void* DataPtr = CVulkanContext::Get()->GetDevice().mapMemory(AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset, Size);
    memcpy(DataPtr, Data, InSize);
    CVulkanContext::Get()->GetDevice().unmapMemory(AutoRecycleBuffer.MemoryBlock.Memory);
}

void CVulkanUniformBuffer::WriteData(const void *Data, uint64_t InSize)
{
    assert(InSize<=Size&&"数据大小超过了UniformBuffer的大小");
    if(InSize==0)
    {
        return;
    }

    void* DataPtr = CVulkanContext::Get()->GetDevice().mapMemory(AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset, Size);
    memcpy(DataPtr, Data, InSize);
    CVulkanContext::Get()->GetDevice().unmapMemory(AutoRecycleBuffer.MemoryBlock.Memory);
}

void CVulkanUniformBuffer::Resize(uint64_t InSize)
{
    if(InSize==Size)
    {
        return;
    }

    if(Size!=0)
    {
        AutoRecycleBuffer.ClearBuffer();
    }

    Size=InSize;

    if(Size>0)
    {
        vk::BufferCreateInfo BufferCreateInfo=vk::BufferCreateInfo()
            .setSize(Size)
            .setUsage(vk::BufferUsageFlagBits::eUniformBuffer)
            .setSharingMode(vk::SharingMode::eExclusive);

        AutoRecycleBuffer.Buffer=CVulkanContext::Get()->GetDevice().createBuffer(BufferCreateInfo);
        vk::MemoryRequirements MemoryRequirements=CVulkanContext::Get()->GetDevice().getBufferMemoryRequirements(AutoRecycleBuffer.Buffer);

        uint32_t MemoryTypeIndex=CVulkanContext::Get()->GetMemoryTypeIndex(MemoryRequirements, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);

        AutoRecycleBuffer.MemoryBlock=CVulkanContext::Get()->GetMemoryPools()->AllocateBlock(
            EVulkanMemoryUsage::UniformBuffer
            ,MemoryTypeIndex
            ,MemoryRequirements
            );

        CVulkanContext::Get()->GetDevice().bindBufferMemory(AutoRecycleBuffer.Buffer, AutoRecycleBuffer.MemoryBlock.Memory, AutoRecycleBuffer.MemoryBlock.Offset);
    }
}